class Game {

    count = 0;
    wins = [];

    black = true;
    over = false;
    chessCount = 0;
    process = [];
    chessBoard = [];
    gobackData = {};
    returnAble = false;

    blackStatus = [];
    whiteStatus = [];

    constructor(doms) {
        this.doms = doms;
        this.ctx = this.doms.oChess.getContext("2d")
    }

    init() {
        this.winMethods();
        this.resetChess();
        this.drawChessBoard();
        this.handleEventListener();
    }

    handleEventListener() {

        this.doms.oChess.addEventListener("click", this.palyChess.bind(this))
        this.doms.oRestart.addEventListener("click", this.restart.bind(this))
        this.doms.oGoback.addEventListener("click", this.goback.bind(this))
        this.doms.oReturn.addEventListener("click", this.return.bind(this))

    }
    palyChess(e){
        if (this.over) {
            return;
        }
        if (this.chessCount == 225) {
            this.doms.oTitle.innerHTML = "此局平局";
            return;
        }
        const i = Math.floor(e.offsetX / 30);
        const j = Math.floor(e.offsetY / 30);
        if (this.chessBoard[i][j] == 0) {
            this.oneStep(i, j, this.black);
            this.chessBoard[i][j] = 1;
            this.black = !this.black;
        }
    }
    restart(){
        this.doms.oTitle.innerHTML = "开始新一轮的游戏，黑子下棋";
        this.resetChess();
    }
    goback(){
        if (!this.process.length) {
            return;
        }
        const roundNum = this.process.length - 1;
        const round = this.process[roundNum];
        const stepNum = round.length - 1;
        const step = stepNum ? this.process[roundNum].pop() : this.process.pop()[0];
        const [i, j] = step;
        const player = this.black ? this.whiteStatus : this.blackStatus;
        for (let k = 0; k < this.count; k++) {
            if (this.wins[i][j][k]) {
                player[k]--;
            }
        }
        this.chessBoard[i][j] = 0;
        this.gobackData = { roundNum, stepNum, step };
        this.returnAble = true;
        this.doms.oReturn.className = "return";
        this.minusStep(i, j);
        this.doms.oTitle.innerHTML = `${this.black ? "白" : "黑"}子悔棋，${this.black ? "白" : "黑"}子下棋`
        this.black = !this.black;
    }
    return(){
        if (!this.returnAble || this.over) {
            return;
        }
        const { roundNum, stepNum, step } = this.gobackData;
        if (stepNum) {
            this.process[roundNum][stepNum] = step;
        } else {
            this.process[roundNum] = [];
            this.process[roundNum][0] = step;
        }
        const [i, j] = step;
        this.oneStep(i, j, this.black);
        const player = this.black ? this.whiteStatus : this.blackStatus;
        for (let k = 0; k < this.count; k++) {
            if (this.wins[i][j][k]) {
                player[k]++;
            }
        }
        this.chessBoard[i][j] = 0;
        this.black = !this.black;
        this.doms.oTitle.innerHTML = `已撤销${this.black ? "白" : "黑"}子悔棋，${this.black ? "黑" : "白"}子下棋`
        this.gobackData = {};
        this.returnAble = false;
        this.doms.oReturn.className = "return unable";
    }

    addProcess(i, j) {
        if (this.returnAble) {
            this.returnAble = false;
            this.doms.oReturn.className = "return unable";
            this.gobackData = {};
        }

        let index = 1;
        if (this.black) {
            this.process[this.process.length] = [];
            index = 0;
        }
        this.process[this.process.length - 1][index] = [];
        this.process[this.process.length - 1][index][0] = i;
        this.process[this.process.length - 1][index][1] = j;
        this.doms.oTitle.innerHTML = `第${this.process.length}回合：${this.black ? "黑" : "白"}子已下，${this.black ? "白" : "黑"}子下棋`
        this.judgeWin(i, j)
    }

    judgeWin(i, j) {
        const player = this.black ? this.blackStatus : this.whiteStatus;
        // 将可能赢的情况都加1
        for (let k = 0; k < this.count; k++) {
            if (this.wins[i][j][k]) {
                player[k]++;
                if (player[k] == 5) {
                    this.doms.oTitle.innerHTML = `恭喜，${this.black ? "黑" : "白"}子赢了！`;
                    this.over = true;
                }
            }
        }
    }

    drawChessBoard() {
        this.ctx.strokeStyle = '#bfbfbf';
        for (let i = 0; i < 15; i++) {
            this.ctx.beginPath();
            this.ctx.moveTo(15 + i * 30, 15);
            this.ctx.lineTo(15 + i * 30, 435);
            this.ctx.stroke();

            this.ctx.beginPath();
            this.ctx.moveTo(15, 15 + i * 30);
            this.ctx.lineTo(435, 15 + i * 30);
            this.ctx.stroke();
        }
    }

    oneStep(i, j, order) {
        this.chessCount++;
        this.ctx.beginPath();
        // 画圆
        this.ctx.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);
        this.ctx.closePath();
        //渐变
        const gradient = this.ctx.createRadialGradient(15 + i * 30 + 2, 15 + j * 30 - 2, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);

        if (order) {
            // 黑棋
            gradient.addColorStop(0, '#0a0a0a');
            gradient.addColorStop(1, '#636766');
        } else {
            // 白棋
            gradient.addColorStop(0, '#d1d1d1');
            gradient.addColorStop(1, '#f9f9f9');
        }
        this.ctx.fillStyle = gradient;
        this.ctx.fill();
        this.addProcess(i, j);
    }

    minusStep(i, j) {
        //擦除该圆
        this.ctx.clearRect((i) * 30, (j) * 30, 30, 30);
        // 重画该圆周围的格子
        this.ctx.beginPath();
        // 竖
        this.ctx.moveTo(15 + i * 30, j == 0 ? 15 + j * 30 : j * 30);
        this.ctx.lineTo(15 + i * 30, j == 14 ? j * 30 + 15 : j * 30 + 30);
        // 横
        this.ctx.moveTo(i == 0 ? 15 + i * 30 : i * 30, j * 30 + 15);
        this.ctx.lineTo(i == 14 ? (i + 1) * 30 - 15 : (i + 1) * 30, j * 30 + 15);
        this.ctx.stroke();
    }

    // 初始化棋盘数组状态
    resetChess() {
        if(this.returnAble){
            this.returnAble = false;
            this.doms.oReturn.className = "return unable";
            this.gobackData = {};
        }
        if (this.process) {
            const len = this.process.length;
            for (let i = 0; i < len; i++) {
                const round = this.process.pop();
                const len = round.length;
                for (let i = 0; i < len; i++) {
                    const step = round.pop();
                    const [i, j] = step;
                    this.minusStep(i, j);
                }
            }
        }
        const chessBoard = [];
        const blackStatus = [];
        const whiteStatus = [];
        for (let i = 0; i < 15; i++) {
            chessBoard[i] = [];
            for (let j = 0; j < 15; j++) {
                chessBoard[i][j] = 0;
            }
        }
        for (let i = 0; i < this.count; i++) {
            blackStatus[i] = 0;
            whiteStatus[i] = 0;
        }
        this.over = false;
        this.black = true;
        this.chessCount = 0;
        this.process = [];
        this.chessBoard = chessBoard;
        this.blackStatus = blackStatus;
        this.whiteStatus = whiteStatus;
    }

    // 遍历所有赢法
    winMethods() {
        //赢法数组
        const wins = [];
        for (let i = 0; i < 15; i++) {
            wins[i] = [];
            for (let j = 0; j < 15; j++) {
                wins[i][j] = [];
            }
        }
        //统计赢法总数
        let count = 0;
        //横线赢法
        for (let i = 0; i < 15; i++) {
            for (let j = 0; j < 11; j++) {
                for (let k = 0; k < 5; k++) {
                    wins[i][j + k][count] = true;
                }
                count++;
            }
        }
        //竖线赢法
        for (let i = 0; i < 15; i++) {
            for (let j = 0; j < 11; j++) {
                for (let k = 0; k < 5; k++) {
                    wins[j + k][i][count] = true;
                }
                count++;
            }
        }
        //正斜线赢法
        for (let i = 0; i < 11; i++) {
            for (let j = 0; j < 11; j++) {
                for (let k = 0; k < 5; k++) {
                    wins[i + k][j + k][count] = true;
                }
                count++;
            }
        }
        //反斜线赢法
        for (let i = 0; i < 11; i++) {
            for (let j = 14; j > 3; j--) {
                for (let k = 0; k < 5; k++) {
                    wins[i + k][j - k][count] = true;
                }
                count++;
            }
        }
        this.wins = wins;
        this.count = count;
    }

}


const oChess = document.querySelector("canvas.chessboard");
const oTitle = document.querySelector(".wrap div.title");
const oRestart = document.querySelector(".button div.restart");
const oGoback = document.querySelector(".button div.goback");
const oReturn = document.querySelector(".button div.return");
new Game({ oChess, oTitle, oRestart, oGoback, oReturn }).init();